from pathlib import Path
import mimetypes
import requests
from requests_toolbelt import MultipartEncoder
from config import settings
from utils.extract_data_handler import *
from utils.yaml_handler import yamler
from utils.log_handler import logger
from utils.validate_handler import assert_result


class RequestHandler(object):
    session = requests.session()

    def __init__(self, obj):
        self.obj = obj

    @staticmethod
    def extract_res_data(res, val):
        for k, v in val.items():
            data = extract_by_object(res, v)
            if data:
                val[k] = data
            else:
                val[k] = ""
                logger.exception(f"获取不到元素，为{k}赋空值")
        yamler.write_data(settings.EXTRACT_RES_FILE_PATH, val)

    @staticmethod
    def upload_file(filepath: Path):
        """根据文件路径，自动获取文件名称和文件mime类型"""
        if not filepath.exists():
            return
        mime_type = mimetypes.guess_type(filepath)[0]
        return (
            filepath.name, filepath.open("rb"), mime_type
        )

    def multipart_encoder_request(self, request_value: dict, root_dir):
        """判断请求头部 Content-Type: multipart/form-data 格式支持"""
        if 'files' in request_value.keys():
            fields = []
            data = request_value.get('data', {})
            fields.extend(data.items())  # 添加data数据
            for key, value in request_value.get('files', {}).items():
                if Path(root_dir).joinpath(value).is_file():
                    fields.append(
                        (key, self.upload_file(Path(root_dir).joinpath(value).resolve()))
                    )
            m = MultipartEncoder(
                fields=fields
            )
            request_value.pop('files')  # 去掉 files 参数
            request_value['data'] = m
            new_headers = request_value.get('headers', {})
            new_headers.update({'Content-Type': m.content_type})
            request_value['headers'] = new_headers
            return request_value
        else:
            return request_value

    def send_request(self, **kwargs):
        try:
            res = self.session.request(**kwargs)
            return res
        except Exception as e:
            logger.error(f"发送请求失败，失败原因为：{e}")

    def get_request_data(self, case_info):

        request_data_keys = case_info["request"].keys()

        if set(request_data_keys).issuperset({"method", "url"}):
            request_data = case_info["request"]
            logger.info(f"开始执行用例：{case_info['title']}")
            logger.info(f"请求方式：{request_data['method']}")
            logger.info(f"请求地址：{request_data['url']}")
            if "files" in request_data.keys():
                request_dic = self.multipart_encoder_request(request_data, settings.UPLOADING_FILE_PATH)
                logger.info(f"请求头：{request_dic['headers']}")
                logger.info(f"请求参数data：{request_dic['data']}")
            else:
                if set(request_data_keys).issuperset({"headers"}):
                    logger.info(f"请求头信息为：{request_data['headers']}")
                for k in request_data.keys():
                    if k == "params":
                        logger.info(f"请求参数params：{request_data['params']}")
                    elif k == "data":
                        logger.info(f"请求参数data：{request_data['data']}")
                    elif k == "json":
                        logger.info(f"请求参数json：{request_data['json']}")
            res = self.send_request(**request_data)
            logger.info(f"请求结果：{res.text}")
            if case_info.get("extract", None):
                self.extract_res_data(res, case_info["extract"])
            if case_info.get("validate", None):
                assert_result(case_info["validate"], res)
            return res
        else:
            logger.error("request参数必须包含method跟url")
            logger.info(f"{case_info['title']}用例请求结束")